'use client';

import { type ReactNode, useEffect, useState } from 'react';
import classNames from 'classnames';
import type { IClientMessage, IPagination } from '@/interfaces';
import { useInfiniteQuery, useMutation } from '@tanstack/react-query';
import useToast from '@/hooks/useToast';
import {
  markMessageRead,
  queryAllMessage,
  removeMessage,
} from '@/services/api';
import { toRelativeTime } from '@/lib/tool';
import GeneralMessage from '@/app/[locale]/message/general';
import Nodata from '@/app/[locale]/common/nodata/nodata';
import type { IMessagePageContext } from '@/contexts/message';
import Spinner from '@/app/[locale]/component/spinner/spinner';

export default function MessagePage(
  this: any,
  { source, translatedFields }: IMessagePageContext,
) {
  const path = source.path;
  const [currentReadMessageId, setCurrentReadMessageId] = useState<number>();
  const [currentRemoveMessageId, setCurrentRemoveMessageId] =
    useState<number>();
  const { show } = useToast();
  const [pages, setPages] = useState<IClientMessage[]>(source.messages.content);

  const queryAllMessageQuery = useInfiniteQuery(
    ['/messages', 'infinite'],
    async (context) => {
      return (await queryAllMessage({
        query: context.pageParam,
      })) as IPagination<IClientMessage>;
    },
    {
      enabled: !!path.user,
      keepPreviousData: true,
      getPreviousPageParam: (firstPage) => {
        if (!firstPage.pageable.previous) {
          return;
        }
        return {
          page: Math.max(firstPage.pageable.page - 1, 0),
        };
      },
      getNextPageParam: (lastPage) => {
        if (!lastPage.pageable.next) {
          return;
        }
        return {
          page: Math.min(lastPage.pageable.page + 1, lastPage.pageable.pages),
        };
      },
      initialData: () => {
        return {
          pages: [source.messages],
          pageParams: [{ page: 0 }],
        };
      },
    },
  );

  const clientMarkMessageReadMutation = useMutation(markMessageRead);
  const clientRemoveMessageMutation = useMutation(removeMessage);

  useEffect(() => {
    if (queryAllMessageQuery.data) {
      setPages(
        queryAllMessageQuery.data.pages
          .flatMap((item) => item.content)
          .map((item) => {
            item._createdOnText = toRelativeTime(item.createdOn);
            return item;
          }),
      );
    }
  }, [queryAllMessageQuery.data]);

  async function onClickRead(item: IClientMessage, index: number) {
    try {
      setCurrentReadMessageId(item.id);
      const { id, state } = item;
      if ('state' in item && state !== 'UNREAD') {
        return;
      }

      await clientMarkMessageReadMutation.mutateAsync({
        id,
      });

      setPages((prevState) => {
        prevState[index].state = 'HAVE_READ';
        return prevState;
      });

      show({
        type: 'SUCCESS',
        message: translatedFields.isReadComplete,
      });
    } catch (e) {
      clientMarkMessageReadMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    } finally {
      setCurrentReadMessageId(undefined);
    }
  }

  async function onClickRemove(item: IClientMessage, index: number) {
    try {
      setCurrentRemoveMessageId(item.id);
      await clientRemoveMessageMutation.mutateAsync({
        id: item.id,
      });

      if (index === pages.length - 1) {
        await queryAllMessageQuery.refetch({ throwOnError: true });

        show({
          type: 'PRIMARY',
          message: translatedFields.isNextPageLoading,
        });
        return;
      }

      setPages((prevState) => {
        prevState.splice(index, 1);
        return prevState;
      });

      show({
        type: 'SUCCESS',
        message: translatedFields.isDeleteComplete,
      });
    } catch (e) {
      clientRemoveMessageMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    } finally {
      setCurrentRemoveMessageId(undefined);
    }
  }

  async function onClickLoadMore() {
    try {
      await queryAllMessageQuery.fetchNextPage();
    } catch (e) {
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  if (pages.length > 0) {
    return (
      <div className="col px-2 py-4">
        <div className="card border-0">
          <div className="card-body container">
            {pages.map((item, index) => {
              return (
                <div
                  key={item.id}
                  className="row z-1"
                  style={{ marginBottom: -2 }}
                >
                  <div className="col-auto px-0 mx-0">
                    <div className="d-flex flex-column align-items-center h-100">
                      <Circle className="">
                        <Circle width={32} height={32} className="">
                          <i
                            className={classNames(
                              'bi bi-envelope-fill fs-5',
                              item.state === 'UNREAD'
                                ? 'text-primary'
                                : 'text-secondary',
                            )}
                          ></i>
                        </Circle>
                      </Circle>
                      <Line className="" />
                    </div>
                  </div>
                  <div className="col-auto px-0 mx-0">
                    <Line reverse className="" />
                  </div>
                  <div className="col p-2 pb-3">
                    <div className="card border-0">
                      <GeneralMessage item={item} />

                      <div className="card-footer border-0">
                        <div className="d-flex align-items-center justify-content-between">
                          <div>{item._createdOnText}</div>
                          <div className="hstack gap-2">
                            <button
                              disabled={currentRemoveMessageId === item.id}
                              onClick={onClickRemove.bind(this, item, index)}
                              type="button"
                              className="btn focus-ring focus-ring-danger text-danger btn-sm"
                            >
                              {currentRemoveMessageId === item.id && (
                                <span
                                  className="spinner-border spinner-border-sm me-2"
                                  role="status"
                                  aria-hidden="true"
                                ></span>
                              )}
                              {translatedFields.deleteMessage}
                            </button>

                            {item.state === 'UNREAD' && (
                              <button
                                disabled={currentReadMessageId === item.id}
                                onClick={onClickRead.bind(this, item, index)}
                                type="button"
                                className="btn focus-ring focus-ring-primary text-primary btn-sm"
                              >
                                {currentReadMessageId === item.id && (
                                  <span
                                    className="spinner-border spinner-border-sm me-2"
                                    role="status"
                                    aria-hidden="true"
                                  ></span>
                                )}
                                {translatedFields.isRead}
                              </button>
                            )}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}

            <div className="my-4">
              <LoadMoreBtn
                onClickLoadMore={onClickLoadMore}
                isLoading={queryAllMessageQuery.isLoading}
              />
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="col px-2 py-4">
      <div className="container-fluid">
        <Nodata />
      </div>
    </div>
  );
}

const Circle = ({
  width,
  height,
  children,
  className,
}: {
  width?: number;
  height?: number;
  children?: ReactNode;
  className?: string;
}) => {
  return (
    <div
      className={classNames(
        'rounded-circle border d-flex align-items-center justify-content-center flex-shrink-0',
        className,
      )}
      style={{ width: width ?? 48, height: height ?? 48 }}
    >
      {children && children}
    </div>
  );
};

const Line = ({
  width,
  height,
  className,
  reverse,
}: {
  width?: number;
  height?: number;
  className?: string;
  reverse?: boolean;
}) => {
  return (
    <div
      className={classNames(
        'border',
        className,
        reverse
          ? 'w-100 border-top border-bottom border-start-0 border-end-0'
          : 'h-100 border-start border-end border-top-0 border-bottom-0',
      )}
      style={
        reverse
          ? {
              width: width && width > 0 ? width + 2 : '12px !important',
              height: height ?? 10,
              marginLeft: -2,
              marginTop: '1.2rem',
            }
          : {
              width: width ?? 10,
              marginTop: -2,
            }
      }
    ></div>
  );
};

const LoadMoreBtn = ({
  onClickLoadMore,
  isLoading,
}: {
  onClickLoadMore: () => void;
  isLoading: boolean;
}) => {
  return (
    <div className="row mt-4 mb-3">
      <div className="col">
        <button
          onClick={onClickLoadMore}
          disabled={isLoading}
          type="button"
          className="btn rounded-pill text-secondary-emphasis w-100"
        >
          {isLoading ? <Spinner /> : <i className="bi bi-three-dots"></i>}
        </button>
      </div>
    </div>
  );
};
